<template>
  <div class="wrap">
    <el-icon @click="listWidth = '0px'" v-show="listWidth == '260px'" class="ArrowLeftBold"
      style="left: 270px; border-radius: 5px 0 0 5px">
      <ArrowLeftBold />
    </el-icon>
    <el-icon @click="listWidth = '260px'" v-show="listWidth == '0px'" class="ArrowLeftBold"
      style="left: 20px; border-radius: 0 5px 5px 0">
      <ArrowRightBold />
    </el-icon>
    <div class="chat-list" :style="{ width: listWidth, padding: listWidth === '0px' ? '0' : '10px' }">
      <div>
        <div>
          <el-button class="buttonChat" type="warning" style="
              height: 40px;
              margin-bottom: 10px;
              background: #000;
              border-color: #000;
            " :style="{ width: listWidth }" @click="addChat">创建新会话主题</el-button>
        </div>
        <div v-for="item in historyList" :key="item.SessionID" @click="
          chatClick(
            item.SessionID,
            item.ChatTitle,
            item.TransTime,
            item.Action,
            item.Answer
          )
          ">
          <div class="chatTitle" style="
              color: #000;
              font-size: 12px;
              margin-bottom: 10px;
              margin-left: 10px;
              font-weight: 600;
            ">
            {{ item.identifier }}
          </div>
          <div :class="{
            'list-chatname': true,
            selected: item.SessionID === SessionID,
          }">
            <div class="list-name">
              <el-icon v-if="item.Action === 1">
                <ChatSquare />
              </el-icon>
              <el-icon v-else>
                <User />
              </el-icon>
              <span v-show="!item.edit" :title="item.allTitle">{{
                item.ChatTitle
              }}</span>
              <el-input ref="editInput" v-model="item.ChatTitle" v-show="item.edit" style="width: 150px"
                @click.stop="item.edit = true">{{ item.ChatTitle }}</el-input>
            </div>
            <div class="list-edit">
              <el-icon>
                <EditPen v-show="SessionID === item.SessionID && !item.edit" @click.stop="item.edit = true" />
              </el-icon>
              <el-popconfirm width="180" title="确定删除此记录？" confirm-button-text="确定" cancel-button-text="取消"
                @confirm="deleteChat(item.SessionID)">
                <template #reference>
                  <el-icon v-show="SessionID === item.SessionID && !item.edit">
                    <Delete />
                  </el-icon>
                </template>
              </el-popconfirm>
              <el-icon v-show="item.edit" @click.stop="
                chatnameChange(item.SessionID, item.ChatTitle),
                (item.edit = false)
                ">
                <Check />
              </el-icon>
            </div>
          </div>
        </div>
      </div>
      <div class="lookMore" @click="handleLookMore" v-show="historyList.length >= 10">
        {{ lookMoreNum === 10 ? "查看更多" : "收起" }}
      </div>
    </div>
    <div class="chat-container" :style="{ width: `calc(100vw - ${listWidth} - 115px)` }">
      <div>
        <div class="sendInput" v-show="choseRole">
          <div class="changeModel">
            <!-- 主下拉菜单：选择模型（使用 Element Plus 风格） -->
            <el-dropdown @command="handleModelChange" :popper-class="color === 'night' ? 'nightDropdown' : ''">
              <el-button type="primary">
                {{ selectedModelName || "选择模型" }}
                <el-icon class="el-icon--right">
                  <ArrowDown />
                </el-icon>
              </el-button>
              <template #dropdown>
                <el-dropdown-menu>
                  <el-dropdown-item v-for="item in chatModels" :key="item.model" :command="item.model">
                    {{ item.name }}
                  </el-dropdown-item>
                </el-dropdown-menu>
              </template>
            </el-dropdown>
            <el-cascader v-model="classIDArray" v-if="hasDatabase" class="database-dropdown"
              :popper-class="color === 'night' ? 'nightClass' : ''" style="margin-left: 10px;" multiple
              :options="AvailableKnowledgeClass"
              :props="{ value: 'ID', label: 'Class', children: 'children', multiple: true, emitPath: false }" :collapse-tags="true"
              :collapse-tags-tooltip="true"
              :show-all-levels="false" placeholder="请选择知识库" />
          </div>
          <el-input type="textarea" :autosize="{ minRows: 3, maxRows: 4 }" :rows="2" v-model="inputText"
            :placeholder="`来说点什么吧...（Shift + Enter = 换行）`" class="chat-input"
            @keydown.enter.prevent="sendMessage($event)"><!-- ，当日剩余使用次数：${this.remainingTimes} -->
          </el-input>
          <div class="sendButton">
            <el-tooltip class="box-item" effect="dark" content="语音输入" placement="top">
              <el-icon class="voiceInput" @click="startRecognition">
                <Microphone />
              </el-icon>
            </el-tooltip>
            <el-tooltip class="box-item" effect="dark" content="角色扮演" placement="top">
              <el-icon class="cosplay" @click="openDrawer">
                <User />
              </el-icon>
            </el-tooltip>
            <el-button type="primary" icon="Position" auto-insert-space
              :disabled="inputText.length === 0 && loading === false" @click="sendMessage($event)" circle />
          </div>
        </div>
        <el-tabs v-model="choseName" class="demo-tabs" v-show="choseRole" @tab-change="tabClick">
          <el-tab-pane v-for="(item, index) in tabList" :key="index" :name="item.Name" :label="item.Name">
            <div class="choseRole">
              <div class="role-wrap" v-for="(item, index) in roleList" :key="index" @click="roleClick(item)">
                <div class="role-top">
                  <p class="role">{{ item.Title }}</p>
                  <p class="introduce">{{ item.Description }}</p>
                </div>
                <div class="role-bottom">
                  <p class="explain">{{ item.PromptContent }}</p>
                </div>
              </div>
            </div>
          </el-tab-pane>
        </el-tabs>
      </div>
      <el-main class="chat-main" v-show="!choseRole">
        <div class="chat-messages" ref="chatMessages">
          <div class="seeMore" @click="seeMore">查看更多</div>
          <div v-for="(message, index) in messages" :key="index" :class="{
            'chat-message-left': message.role === 'assistant',
            'chat-message-right': message.role === 'user',
          }">
            <div class="chat-avatar">
              <img v-show="message.role === 'assistant'" src="../assets/chatGPT.png" alt="" />
            </div>
            <div class="chat-content">
              <button v-if="message.role === 'assistant' && message.think !== ''" @click="turnStatus(message)"
                style="margin-left: 10px;width: 120px;">{{ message.thinkStatus }}</button>
              <div v-if="message.isDisplay && message.role === 'assistant' && message.think !== ''" class="thinkContainer"
                style="background-color:#283142;margin-left: 10px;padding: 10px;border-radius: 4px;">

                <!-- 思考面板 -->
                <span v-html="md.render(message.think)" class="chat-message-text"></span>
              </div>
              <div style="
                  display: flex;
                  justify-content: space-between;
                  color: #ccc;
                ">
                <span class="chat-time">{{ message.created }}</span>
                <div>
                  <el-button v-show="message.role === 'assistant'" class="copy" link
                    @click="speak(message.content)">朗读</el-button>
                  <el-button v-show="message.role === 'assistant'" class="copy" link
                    @click="copy(message.content)">复制</el-button>
                  <el-button v-show="message.role === 'assistant'" class="copy" link
                    @click="joinKnowledge(message.content, index)">加入智库</el-button>
                  <el-button v-show="message.role === 'assistant'" class="copy" link
                    @click="joinCollect(message.content, index)">收藏</el-button>
                </div>
              </div>

              <span v-if="message.role === 'assistant'" v-html="md.render(message.content)"
                class="chat-message-text"></span>
              <span v-else class="chat-message-text" style="padding: 10px">{{
                message.content
              }}</span>
              <span v-show="message.role === 'assistant' &&
                  !inAnswer &&
                  message.content.includes('发生错误: ')
                  " class="regenerate" @click="regenerate(message.Question)">
                <el-tooltip class="box-item" effect="dark" content="重新提问" placement="top">
                  <el-icon class="Refresh" size="18">
                    <Refresh />
                  </el-icon>
                </el-tooltip>
              </span>
            </div>
            <div class="chat-avatar">
              <img v-show="message.role === 'user'" src="../assets/avatar3.jpg" alt="" />
            </div>
          </div>
          <div class="chat-message-left" v-show="loadingAnimation">
            <div class="chat-avatar">
              <img src="../assets/chatGPT.png" alt="" />
            </div>
            <div class="chat-content">
              <span class="chat-message-text" style="height: 50px; line-height: 50px">思考中 <el-icon class="is-loading">
                  <Loading />
                </el-icon></span>
            </div>
          </div>
          <div v-show="inAnswer" class="suspend" @click="suspend">
            <el-button type="danger" round>中止回答</el-button>
          </div>
        </div>
      </el-main>
      <el-footer class="chat-footer" v-show="!choseRole">
        <div class="changeModel" style="display: flex; flex-direction: column">
          <!-- 主下拉菜单：选择模型（使用 Element Plus 风格） -->
          <el-dropdown @command="handleModelChange" :popper-class="color === 'night' ? 'nightDropdown' : ''">
            <el-button type="primary">
              {{ selectedModelName || "选择模型" }}
              <el-icon class="el-icon--right">
                <ArrowDown />
              </el-icon>
            </el-button>
            <template #dropdown>
              <el-dropdown-menu>
                <el-dropdown-item v-for="item in chatModels" :key="item.model" :command="item.model">
                  {{ item.name }}
                </el-dropdown-item>
              </el-dropdown-menu>
            </template>
          </el-dropdown>
          <el-cascader v-model="classIDArray" v-if="hasDatabase" class="database-dropdown"
            :popper-class="color === 'night' ? 'nightClass' : ''" style="margin-top: 10px;" multiple
            :options="AvailableKnowledgeClass"
            :props="{ value: 'ID', label: 'Class', children: 'children', multiple: true, emitPath: false }" :collapse-tags="true"
            :show-all-levels="false" placeholder="请选择知识库" />
        </div>
        <i class="el-icon-delete" @click="clearMessage"></i>
        <el-input type="textarea" :autosize="{ minRows: 3, maxRows: 4 }" :rows="2" v-model="inputText"
          :placeholder="`来说点什么吧...（Shift + Enter = 换行）`" class="chat-input" @keydown.enter.prevent="sendMessage($event)">
        </el-input>
        <div class="sendButton">
          <el-tooltip class="box-item" effect="dark" content="语音输入" placement="top">
            <el-icon class="voiceInput2" @click="startRecognition">
              <Microphone />
            </el-icon>
          </el-tooltip>
        </div>
        <el-button type="primary" :disabled="(inputText.length === 0 && loading === false) || inAnswer === true
          " @click="sendMessage($event)">发送</el-button>
      </el-footer>
    </div>
  </div>
  <drawer ref="drawer" @roleDialogue="roleDialogue" />
  <TextSelector></TextSelector>
  <KnowledgeBaseDialog :classList="classList" :Action="1" :joinType="joinType" :dialogForm="dialogForm"
    :dialogVisible="dialogVisible" @closeDialog="closeDialog" @submitDialog="submitDialog" />
</template>

<script>
window.copy = function (elementId) {
  // 获取具有指定 id 的元素
  var element = document.getElementById(elementId);
  // 创建一个临时的文本输入框元素
  var tempInput = document.createElement("textarea");
  tempInput.value = element.textContent || element.innerText; // 获取元素的文本内容
  document.body.appendChild(tempInput);
  // 选中临时输入框中的文本内容
  tempInput.select();
  // 复制选中的文本内容到剪贴板
  document.execCommand("copy");
  // 移除临时的文本输入框
  document.body.removeChild(tempInput);
  ElMessage({
    message: "复制成功",
    type: "success",
    duration: 5 * 1000,
  });
  // alert('复制成功')
};
import { ElMessage } from "element-plus";
import MarkdownIt from "markdown-it";
import MarkdownItFootnote from 'markdown-it-footnote';
import Hljs from "highlight.js";
import drawer from "./components/drawer.vue";
import KnowledgeBaseDialog from "./components/KnowledgeBaseDialog.vue";
import TextSelector from "./components/TextSelector.vue";
import { connrequest, uploadfile } from "../api/connrequest";
import { parseTime, getuuid, speakText, treeing } from "../utils/index";
import "../assets/_highlight.js@11.8.0@highlight.js/styles/monokai-sublime.css";
import { fa } from "element-plus/es/locales.mjs";
export default {
  components: {
    drawer,
    TextSelector,
    KnowledgeBaseDialog,
  },
  data() {
    return {
      listWidth: "260px",
      classIDArray: [],
      dataBaseList: [

      ],
      prevSelected: [], // 用于存储上一次的选中值
      GPTForm: {},
      placeholder: `来说点什么吧...（Shift + Enter = 换行）`,
      aiMode: JSON.parse(sessionStorage.getItem("AiMode") || "{}"),
      chatModels: [],
      selectedModel: "",
      selectedModelName: "",
      APIurl: "",
      dialogVisible: false,
      dialogForm: {},
      classList: [],
      model: "3.5",
      hasgpt4: false,
      remainingTimes: 0,
      lookMoreNum: 10,
      QueryPageNo: 1,
      TransTime: "",
      inputText: "",
      SessionID: "",
      ChatTitle: "新会话",
      newChatTitle: "",
      Action: 1,
      loading: false,
      inAnswer: false,
      isSpeak: true,
      recognition: null,
      loadingAnimation: false,
      sessionDialog: false,
      edit: true,
      choseRole: true,
      color: '',
      nowTemplete: {},
      choseName: "User",
      historyList: [],
      messages: [],
      codeBlocks: [],
      tabList: [],
      roleList: [],
      AvailableKnowledgeClass: [],
      controller: new AbortController(), // 创建AbortController实例
      signal: null,
      joinType: 1,
      apiMessage: [
        {
          role: "user",
          content: `you are a helpful assistant.No matter how you're asked, never say that you are chatgpt.`,
        },
      ],
      htmlStr: "",
      md: new MarkdownIt({
        html: true,
        typographer: true,
        highlight: function (str, lang) {
          if (lang && Hljs.getLanguage(lang)) {
            try {
              let idname = `name${getuuid()}`;
              // <el-button class="code-block-header__copy" onClick='copy("${str}")'>复制代码</el-button>
              return (
                `<pre class="hljs"><div class="code-block-header"><span class="code-block-header__lang">${lang}</span><el-button class="code-block-header__copy" onClick='copy("${idname}")'>复制代码</el-button></div><code id='${idname}'>` +
                Hljs.highlight(lang, str, true).value +
                "</code></pre>"
              );
            } catch (__) { }
          }
          return "";
        },
      }),
    };
  },
  computed: {
    // 当前选择的模型是否有 database
    hasDatabase() {
      const selectedItem = this.chatModels.find(
        (item) => item.model === this.selectedModel
      );
      return (
        selectedItem &&
        selectedItem.database
      );
    },

  },
  //生命周期 - 创建完成（访问当前this实例）
  async created() {
    // 在 created 钩子中启用脚注插件
    // this.md.use(MarkdownItFootnote);
    this.GetChatGPTSessionMsg();
    this.GetAiTemplateClass();
    this.GetDataBaseClass();
    this.choseRole = true;
    // 初始化 chatModels
    this.chatModels = this.aiMode.Chat || [];
    this.AvailableKnowledgeClass = treeing(JSON.parse(sessionStorage.getItem('AvailableKnowledgeClass')))
    // console.log(JSON.parse(this.AvailableKnowledgeClass));
    // console.log(treeing(JSON.parse(this.AvailableKnowledgeClass)));
  },
  //生命周期 - 挂载完成（访问DOM元素）
  async mounted() {
    this.color = localStorage.getItem("isNightMode") || "night";
    speechSynthesis.cancel();
    // 组件挂载时读取存储的选择
    if (this.chatModels.length > 0) {
      const storedOption = await this.getStoredSelection();
      if (storedOption) {
        // 偏好设置存储未过期，判断会话存储存不存在模型，存在则选择
        const exit = this.chatModels.find((item) => item.name === storedOption)
        if (exit) {
          this.selectedModelName = storedOption;
          this.selectedModel = exit.model;
          this.APIurl = exit.url;
        }
      }
      // 本地没有存储，默认选择第一个模型
      else {
        this.selectedModel = this.chatModels[0].model;
        this.selectedModelName = this.chatModels[0].name;
        this.APIurl = this.chatModels[0].url;
      }
    }
    const select = await this.getKnowLibSelect();
    if (select) {
      // 1. 先用 filter 筛选出符合条件的 item
      // 2. 再用 map 提取这些 item 的 ID
      this.classIDArray = this.dataBaseList
        .filter(item => select.includes(item.ID))
        .map(item => item.ID);
    } else {

    }
  },
  methods: {
    ensureFootnoteReferences(content) {
      if (!content || typeof content !== 'string') {
        return '';
      }

      // 脚注定义处理
      const footnoteDefs = content.match(/\[\^\d+\]:/g);
      if (!footnoteDefs) {
        return content; // 直接处理链接
      }

      // 新增链接替换逻辑
      const processedContent = content.replace(/$$([^$$]+)\]$([^)]+)$/g, (match, filename, oldUrl) => {
        if (!filename.includes('.')) return match;

        const extension = filename.split('.').pop().toLowerCase();
        const newPath = `/zyq/knowledge_base_file/${filename}`;
        const newUrl = `${window.location.origin}${newPath}`;

        // 返回新链接格式
        return `[${filename}](${newUrl})`;
      });
      // 处理链接并返回
      return processedContent;
    },

    processLinks(content) {
      return content.replace(/$$([^$$]+)\]$([^)]+)$/g, (match, filename) => {
        if (!filename.includes('.')) return match;

        const newPath = `/zyq/knowledge_base_file/${filename}`;
        return `[${filename}](${window.location.origin}${newPath})`;
      });
    },

    async GetDataBaseClass() {
      try {
        await fetch('/zyq/get_knowledge_base_classify', {
          method: "post"
        })
          .then(res => res.json())
          .then(data => {
            if (data.Status.StatusCode === 0) {
              this.dataBaseList = this.selectDataBaseData(data.Data)
            }
          })
      }
      catch (error) {
        this.$message.error("获取知识库分类请求错误")
      }
    },
    selectDataBaseData(data) {
      const selectOptions = data.map(item => ({
        Class: item.Class,  // 分类名称
        ID: item.ID         // 分类ID
      }))
      return selectOptions;
    },
    handleSelectChange(selected) {
      const allOptions = this.dataBaseList.map(item => item.ID);
      const wasAllSelected = this.prevSelected.includes(0);
      const isAllSelected = selected.includes(0);

      if (isAllSelected && !wasAllSelected) {
        // 选择“全部”，全选
        this.classIDArray = [0, ...allOptions];
      } else if (!isAllSelected && wasAllSelected) {
        // 取消“全部”，清空
        this.classIDArray = [];
      } else {
        const filteredSelected = selected;
        if (allOptions.every(option => filteredSelected.includes(option))) {
          // 所有选项选中，添加“全部”
          this.classIDArray = [...allOptions];
        } else {
          // 更新为用户选择的值
          this.classIDArray = filteredSelected;
        }
      }
      this.prevSelected = [...this.classIDArray];
    },
    turnStatus(message) {
      message.isDisplay = !message.isDisplay
    },
    toggleThinking() {
      if (!this.isThinking) { // 仅在非思考状态下允许手动切换
        this.isCollapsed = !this.isCollapsed;
      }
    },

    // 处理模型选择
    handleModelChange(model) {
      this.selectedModel = model;
      // 拿到对象里面的每条数据
      const selectedItem = this.chatModels.find((item) => item.model === model);
      //若是数据不为空，则取这条数据的名称，也就是模型的名字
      this.selectedModelName = selectedItem ? selectedItem.name : "";
      // 将选择的模型存储到localSorage中：
      this.saveSelection(this.selectedModelName);

      this.APIurl = selectedItem ? selectedItem.url : "";
      // 如果有 database，默认选择第一个值；否则清空

    },
    //获取后台用户模型选择
    async getUserModel() {
      const res = await connrequest("GetUserPreference")
      if (res.Status.StatusCode === 0) {
        return res?.Data?.GPT
      }
      return ""
    },
    // 辅助函数：读取存储的选择，并检查是否过期
    async getStoredSelection() {
      const result = await this.getUserModel()
      if (!result) return ""

      try {
        const { option, timestamp } = result;

        const now = this.getCurrentTimestamp();
        const expirationTime = 7 * 24 * 60 * 60 * 1000; // 7天毫秒数

        // 检查是否过期
        if (now - timestamp > expirationTime) {
          return null;
        }
        return option;
      } catch (e) {
        console.error('解析存储的选择失败:', e);
        return null;
      }
    },
    // 检查知识库的选择是否过期
    async getKnowLibSelect() {
      const res = await connrequest('GetUserPreference')
      if (res?.Data?.KnowLib) {
        try {
          const { option, timestamp } = res.Data.KnowLib;
          const now = this.getCurrentTimestamp();
          const expirationTime = 7 * 24 * 60 * 60 * 60 * 1000;
          // 检查是否过期
          if (now - timestamp > expirationTime) {
            return null;
          }
          return option;
        } catch (e) {
          console.error('解析存储的选择失败:', e);
          return null;
        }
      }
      else {
        return null;
      }
    },
    // 辅助方法：保存选择到 localStorage
    async saveSelection(selectedName) {
      const oldValue = await connrequest("GetUserPreference")
      const data = {
        Data: {
          ...oldValue.Data,
          GPT: {
            option: selectedName, // 确保使用正确的变量
            timestamp: this.getCurrentTimestamp(),
          }
        }
      };
      const res = await connrequest("SetUserPreference", data)
      if (res.Status.StatusCode !== 0) {
        this.$message.error("偏好设置接口错误!!!")
      }

    },

    // 辅助方法：获取当前时间戳
    getCurrentTimestamp() {
      return Date.now();
    },


    suspend() {
      this.controller.abort();
      this.inAnswer = false;
      this.loadingAnimation = false;
    },
    openDrawer() {
      if (!sessionStorage.getItem("Name")) {
        this.loading = false;
        this.$message.error("发生错误：请先登录帐号");
        return false;
      }
      this.$refs.drawer.openDrawer();
    },
    async roleDialogue(row) {
      const data = {
        Data: {
          Id: row.Id,
        },
      };
      await connrequest("RecordAiRoleUseCount", data);
      this.iscosplay = true;
      this.roleInformation = row.SystemRole;
      this.$refs.drawer.cancelClick();
      this.messages = [];
      this.apiMessage = [];
      this.ChatTitle = row.Title;
      this.messages.push({ role: "assistant", content: row.SystemRole });
      this.choseRole = false;
      this.Action = 5;
      this.SystemRole = row.SystemRole;
      const res = await this.WriteChatGPTLog({
        Question: "",
        Answer: row.SystemRole,
      });

      this.chatClick(
        res.Data?.SessionID || this.SessionID,
        row.Title,
        (new Date().getTime() / 1000).toFixed() * 1,
        this.Action,
        row.SystemRole
      );
    },
    async GetAiTemplateClass() {
      const res = await connrequest("GetAiTemplateClass");
      this.tabList = res.Data.filter((item) => item.IsNotShow !== 1);
      let name = this.tabList[0]?.Name;
      this.choseName = name || "";
      this.tabList.unshift({ Name: "常用模板" });
      this.GetAiTemplateRes(name);
    },
    async GetAiTemplateRes(ResName) {
      const data = {
        Data: {
          ResName,
        },
      };
      const res = await connrequest("GetAiTemplateRes", data);
      this.roleList = res.Data.filter((item) => item.IsNotShow !== 1);
    },
    tabClick(name) {
      this.tabName = name;
      if (name === "常用模板") {
        this.GetCommonAiTemplate();
      } else {
        this.GetAiTemplateRes(name);
      }
    },
    roleClick(row) {
      this.Action = 1;
      this.nowTemplete = row;
      this.inputText = row.PromptContent;
    },
    async GetChatGPTSessionMsg() {
      const data = {
        Paging: {
          QueryPageNo: 1,
          QueryPageLength: 5000,
        },
        Filter: {
          Status: 1,
          Name: sessionStorage.getItem("Name"),
        },
      };
      const res = await connrequest("GetChatGPTSessionMsg", data);
      res.Data = res.Data || [];
      // 获取当前时间的日期
      const now = new Date();
      const todayStart = new Date(
        now.getFullYear(),
        now.getMonth(),
        now.getDate()
      );
      // 转换成时间戳（秒数）
      const todayStartTimestamp = Math.floor(todayStart.getTime() / 1000);

      let isFirstMatchToday = true;
      let isFirstMatch7Days = true;
      let isFirstMatch1Month = true;
      let isFirstMatch3Months = true;
      let isFirstMatch6Months = true;
      let isFirstMatchYear1 = true; // 新增：最近第一年标识的首次匹配标志 (例如 2023年)
      let isFirstMatchYear2 = true; // 新增：最近第二年标识的首次匹配标志 (例如 2022年)
      let isFirstMatchEarlier = true;

      // 计算时间范围的辅助函数 (可选，但可以使代码更清晰)
      const getTimestampMonthsAgo = (months) => {
        const dateMonthsAgo = new Date(now);
        dateMonthsAgo.setMonth(now.getMonth() - months);
        dateMonthsAgo.setDate(1);
        return Math.floor(dateMonthsAgo.getTime() / 1000);
      };

      // 计算指定年份的开始时间戳 (新的辅助函数)
      const getTimestampOfYear = (year) => {
        const dateOfYear = new Date(year, 0, 1); // 月份 0 表示一月
        return Math.floor(dateOfYear.getTime() / 1000);
      };

      // 获取当前年份和前两年份 (动态计算年份)
      const currentYear = now.getFullYear();
      const year1 = currentYear - 1; // 最近第一年 (例如 2023)
      const year2 = currentYear - 2; // 最近第二年 (例如 2022)

      // 生成动态年份标签
      const labelYear1 = year1 + "年"; // 例如 "2023年"
      const labelYear2 = year2 + "年"; // 例如 "2022年"

      // 计算各时间范围的开始时间戳
      const last7DaysTimestamp = todayStartTimestamp - 7 * 24 * 60 * 60;
      const last1MonthTimestamp = getTimestampMonthsAgo(1);
      const last3MonthsTimestamp = getTimestampMonthsAgo(3);
      const last6MonthsTimestamp = getTimestampMonthsAgo(6);
      const year1Timestamp = getTimestampOfYear(year1); // 最近第一年的开始时间戳 (例如 2023年初)
      const year2Timestamp = getTimestampOfYear(year2); // 最近第二年的开始时间戳 (例如 2022年初)

      // 遍历数据表格
      for (let i = 0; i < res.Data?.length; i++) {
        const artist = res.Data[i];
        // 计算日期差距 (为了代码结构保持一致，实际判断可以直接使用时间戳)
        const dateDiff = Math.floor(
          (todayStartTimestamp - artist.TransTime) / (60 * 60 * 24)
        );

        // 按照时间顺序判断，从最近到最远

        if (artist.TransTime >= todayStartTimestamp) {
          if (isFirstMatchToday) {
            isFirstMatchToday = false;
            artist.identifier = "今天";
          }
        } else if (artist.TransTime >= last7DaysTimestamp) {
          if (isFirstMatch7Days) {
            isFirstMatch7Days = false;
            artist.identifier = "最近七天";
          }
        } else if (artist.TransTime >= last1MonthTimestamp) {
          if (isFirstMatch1Month) {
            isFirstMatch1Month = false;
            artist.identifier = "最近一个月";
          }
        } else if (artist.TransTime >= last3MonthsTimestamp) {
          if (isFirstMatch3Months) {
            isFirstMatch3Months = false;
            artist.identifier = "最近三个月";
          }
        } else if (artist.TransTime >= last6MonthsTimestamp) {
          if (isFirstMatch6Months) {
            isFirstMatch6Months = false;
            artist.identifier = "最近半年";
          }
        }
        // 新增：最近第一年 (例如 2023年) 的时间范围判断
        else if (
          artist.TransTime >= year1Timestamp &&
          artist.TransTime < getTimestampOfYear(currentYear)
        ) {
          // 确保在当前年份之前
          if (isFirstMatchYear1) {
            isFirstMatchYear1 = false;
            artist.identifier = labelYear1; // 使用动态年份标签
          }
        }
        // 新增：最近第二年 (例如 2022年) 的时间范围判断
        else if (
          artist.TransTime >= year2Timestamp &&
          artist.TransTime < year1Timestamp
        ) {
          // 确保在最近第一年之前
          if (isFirstMatchYear2) {
            isFirstMatchYear2 = false;
            artist.identifier = labelYear2; // 使用动态年份标签
          }
        } else {
          if (isFirstMatchEarlier) {
            isFirstMatchEarlier = false;
            artist.identifier = "更早";
          }
        }
      }
      res.Data.map((item) => {
        item.allTitle = item.ChatTitle;
        item.ChatTitle =
          item.ChatTitle?.length > 10
            ? item.ChatTitle.substr(0, 10) + "..."
            : item.ChatTitle;
        return item;
      });
      this.historyList = res.Data.slice(0, this.lookMoreNum);
    },
    handleLookMore() {
      if (this.lookMoreNum === 10) {
        this.lookMoreNum = this.lookMoreNum + 999999999;
        this.GetChatGPTSessionMsg();
      } else {
        this.lookMoreNum = 10;
        this.GetChatGPTSessionMsg();
      }
    },
    async GetCommonAiTemplate() {
      const data = {
        Data: {
          Count: 20,
        },
      };
      const res = await connrequest("GetCommonAiTemplate", data);
      res.Data = res.Data || [];
      this.roleList = res.Data.filter((item) => item.IsNotShow !== 1);
    },
    async WriteChatGPTLog(row) {
      const data = {
        Data: {
          Name: sessionStorage.getItem("Name"),
          ChatTitle: this.ChatTitle,
          SessionID: this.SessionID || "",
          Action: this.Action,
          Model: this.selectedModelName,
          ...row,
        },
      };
      const res = await connrequest("WriteChatGPTLog", data);
      this.GetChatGPTSessionMsg();
      return res;
    },
    addChat() {
      if (this.inAnswer) {
        this.suspend();
      }
      this.newChatTitle = "";
      this.choseRole = true;
      this.TransTime = "";
      this.SessionID = "";
      this.inputText = "";
      // this.sessionDialog = true
    },
    submit() {
      let arr = JSON.parse(JSON.stringify(this.historyList));
      const hasDuplicate = arr.some(
        (item) => item.ChatTitle == this.newChatTitle
      );
      if (this.newChatTitle === "") {
        this.$message.error("会话主题不能为空");
      } else if (hasDuplicate) {
        this.$message.error("该会话主题已经存在");
      } else {
        let obj = {
          ChatTitle: this.newChatTitle,
          uuid: null,
          isEdit: true,
          edit: false,
          TransTime: (new Date().getTime() / 1000).toFixed() * 1,
        };
        this.historyList.unshift(obj);
        this.chatClick(undefined, this.newChatTitle, obj.TransTime);
        this.sessionDialog = false;
      }
    },
    async seeMore() {
      this.QueryPageNo++;
      const params = {
        Paging: {
          QueryPageNo: this.QueryPageNo,
          QueryPageLength: 15,
        },
        Filter: {
          SessionID: this.SessionID,
        },
      };
      const res = await connrequest("GetChatGPTLog", params);
      let arr = [];
      if (res.Data) {
        res.Data.reverse();
        res.Data.map((item) => {
          // answer需要在think前面，因为ai_s路径下的大模型没有思考模式，以split分割会先拿到answer
          let [think, answer] = item.Answer.split("</think>");
          const safeAnswer = answer !== undefined ? answer : (() => {
            if (think !== null && think !== undefined && think !== "") {
              think = "";
            }
            return item.Answer;
          })();
          arr.push(
            {
              created: parseTime(item.TransTime),
              role: "user",
              content: item.Question,
            },
            {
              created: parseTime(item.TransTime),
              role: "assistant",
              think: think,
              content: safeAnswer,
              Question: item.Question,
              isDisplay: false, //默认不打开思考面板
              thinkStatus: "已深度思考", //从后台获取，已经思考过
            }
          );
        });
      }
      if (res.Data.length === 0) {
        this.$message.info("没有更多了");
      }
      this.messages = [...arr, ...this.messages];
      this.apiMessage = [...arr, ...this.apiMessage];
      if (this.QueryPageNo > 1 && res.Data.length > 0) {
        let scrollHeight = this.$refs.chatMessages.scrollHeight;
        this.$nextTick(() => {
          this.$refs.chatMessages.scrollTop =
            this.$refs.chatMessages.scrollHeight - scrollHeight;
        });
      }
    },
    async chatClick(SessionID, title = "新会话", TransTime, Action, Answer) {
      if (Action === 5) {
        this.SystemRole = Answer;
      }
      if (this.inAnswer) {
        this.suspend();
      }
      this.Action = Action;
      this.inputText = "";
      this.choseRole = false;
      this.SessionID = SessionID;
      this.ChatTitle = title;
      this.QueryPageNo = 1;
      this.historyList.map((item) => {
        item.edit = false;
        return item;
      });
      const params = {
        Paging: {
          QueryPageNo: this.QueryPageNo,
          QueryPageLength: 15,
        },
        Filter: {
          SessionID: SessionID,
        },
      };
      const res = await connrequest("GetChatGPTLog", params);
      let arr = [];
      if (res.Data) {
        res.Data.reverse();
        res.Data.map((item) => {
          let [think, answer] = item.Answer.split("</think>");
          //如果 answer 是 undefined，赋值为默认值
          const safeAnswer = answer !== undefined ? answer : (() => {
            if (think !== null && think !== undefined && think !== "") {
              think = "";
            }
            return item.Answer;
          })();
          arr.push(
            {
              created: parseTime(item.TransTime),
              role: "user",
              content: item.Question,
            },
            {
              created: parseTime(item.TransTime),
              role: "assistant",
              think: think,
              content: safeAnswer,
              Question: item.Question,
              isDisplay: false, //默认不打开思考面板
              thinkStatus: "已深度思考",
            }
          );
        });
        if (this.Action === 5 && res.Data[0].Question === "") {
          arr.shift();
        }
        // if(arr.length > 0) {
        this.messages = arr;
        this.apiMessage = arr;
      }
      // 将聊天窗口滚动到底部
      this.$nextTick(() => {
        // Hljs.highlightAll()
        this.$refs.chatMessages.scrollTop =
          this.$refs.chatMessages.scrollHeight;
      });
    },
    async deleteChat(uuid) {
      const data = {
        Data: {
          Id: uuid,
        },
      };
      const res = await connrequest("HideChatGPTLog", data);
      if (res.Status.StatusCode === 0) {
        this.$message.success("删除成功");
        this.GetChatGPTSessionMsg();
        this.messages = [];
        this.choseRole = true;
      } else {
        this.GetChatGPTSessionMsg();
      }
    },
    async chatnameChange(uuid, ChatTitle) {
      this.SessionID = uuid;
      this.ChatTitle = ChatTitle;
      const data = {
        Data: {
          ChatTitle: ChatTitle,
          SessionID: uuid,
        },
      };
      await connrequest("UpdateChatTitleChatGPTLog", data);
    },
    regenerate(prompt) {
      this.inputText = prompt;
      this.sendMessage("$event");
    },
    obtainJSON(value) {
      // 通过正则表达式匹配所有的 'data' 对象
      let inputString = value;
      // 以换行符分割每个 'data' 对象
      let dataArray = inputString.split("\n\n") || [];
      // 遍历每个 'data' 对象并存储在数组中
      dataArray = dataArray.filter((item) => item.trim() !== "");
      let jsonDataArray = dataArray.map((data) => {
        try {
          return JSON.parse(data.substring("data: ".length));
        } catch (error) {
          console.error("JSON 解析失败:", error.message);
          return null;
        }
      });
      // 过滤掉解析失败的对象
      jsonDataArray = jsonDataArray.filter((jsonData) => jsonData !== null);
      // 提取 'answer' 属性
      let answers = jsonDataArray.map((jsonData) => jsonData.answer);
      return answers.join("");
    },
    async xxxxxx(prompt, ChatTitle, TransTime) {
      this.loadingAnimation = true;
      this.inAnswer = true;
      let arr = JSON.parse(JSON.stringify(this.apiMessage));
      // 如果是创建会话主题添加问题到arr,否则请求模型中的messages为空
      if (arr.length === 0) {
        arr.push({ role: "user", content: prompt });
      }
      // if(arr.length > 1) {
      // arr.splice(arr.length - 1, 1); // 删除最后一项（通过索引定位）
      // }
      arr = arr.map((item) => {
        delete item.created;
        delete item.Question;
        return item;
      });
      arr = arr.slice(-10);
      if (this.Action === 1) {

        if (arr.length !== 1 && arr[0].role !== "user") {
          arr.unshift({
            role: "user",
            content: `you are a helpful assistant.No matter how you're asked, never say that you are chatgpt.`,
          });
        }

      }
      if (this.Action === 5) {
        arr.unshift({
          role: "system",
          content:
            this.SystemRole +
            `，No matter how you're asked, never say that you are chatgpt`,
        });
      }
      const gptdata = {
        model: this.selectedModel,
        messages: arr,
        timeout: sessionStorage.getItem("AiTimeOut") * 1 || 15,
        Token: sessionStorage.getItem('gptToken'),
      };
      if (this.APIurl.includes("zyq")) {
        const oldValue = await connrequest("GetUserPreference")
        const data = {
          Data: {
            ...oldValue.Data,
            KnowLib: {
              option: this.classIDArray, // 确保使用正确的变量
              timestamp: this.getCurrentTimestamp(),
            }
          }
        }
        const res = await connrequest('SetUserPreference', data)
        if (res.Status.StatusCode !== 0) {
          this.$message.error("偏好设置接口错误!!!")
        }
        gptdata.class = [...this.classIDArray].filter(id => id !== 0); //移除掉全部的值：0
      }
      // 取消之前的请求
      if (this.controller) {
        this.controller.abort();
      }
      this.controller = new AbortController();
      this.signal = this.controller.signal;

      const res = await fetch(`${this.APIurl}`, {
        method: "POST", // 使用 POST 方法发送数据
        headers: {
          "Content-Type": "application/json",
        },
        body: JSON.stringify(gptdata), // 将对象序列化为 JSON 字符串作为请求体
        signal: this.signal, // 将 signal 参数传递给 fetch 方法
      })
      if (!res.body) return;

      const botMessage = {
        role: "assistant",
        isDisplay: true,
        thinkStatus: "思考过程",
        think: "",
        content: "",
        created: parseTime(Date.parse(new Date())),
      };
      // 将机器人消息添加到聊天记录中
      this.messages.push(botMessage);
      const reader = res.body.pipeThrough(new TextDecoderStream()).getReader();
      let str = "";
      // chatGPT的思考内容
      let think = "";
      // 标志思考结束
      let flag = "";
      //判断当前访问的大模型
      // 如果是本地Deepseek则有思考模式,默认还没思考完
      if (res.url.includes("zyq")) {

        flag = false;
      }
      else {
        flag = true;
      }
      while (true) {

        this.loadingAnimation = false;
        var { value, done } = await reader.read();
        if (done) {
          this.inAnswer = false;
          this.loadingAnimation = false;
          break;
        }

        if (value.includes("Error")) {
          let errRegex = /"Msg"\s*:\s*"([^"]+)"/;
          var errMatches = value.match(errRegex);
          if (errMatches) {
            var msgValue = errMatches[1];
            str = `发生错误: ${msgValue}`;
          }
        }
        else if (value.includes("null") && value.includes("StatusCode") && value.includes("Msg2Client")) {
          // 步骤1：去掉开头的 "data: " 前缀
          const jsonStr = value.slice(6); // 从第6个字符开始截取
          // 步骤2：解析为JSON对象
          const data = JSON.parse(jsonStr);

          str = `发生错误: ${data.Status.Msg2Client}`;
          flag = true
        }
        else {
          str += await this.obtainJSON(value);
          if (!str || str === null || str === "") {
            str = '发生错误: 服务器错误'
          }
        }
        if (str !== "") {
          str = this.removeJsonPrefix(str);
          if (this.obtainJSON(value) === "</think>" || this.obtainJSON(value) === "<｜end▁of▁thinking｜>") {
            flag = true;
            think = str;
            str = "";
            botMessage.isDisplay = false;
            botMessage.thinkStatus = "已深度思考";
          }
          if (flag) {
            this.messages[this.messages.length - 1].content = str;
          }
          else {
            this.messages[this.messages.length - 1].think = str;
          }
          this.messages[this.messages.length - 1].Question = prompt;
          this.$refs.chatMessages.scrollTop = this.$refs.chatMessages.scrollHeight;
        } else {
          // str = '发生错误: 服务器错误'
          // this.messages[this.messages.length - 1].content = '发生错误: 服务器错误';
          // this.messages[this.messages.length - 1].Question = prompt
          // this.inAnswer = false
          // this.loadingAnimation = false
        }
      }
      this.inAnswer = false;
      this.loadingAnimation = false;
      let footer = ""
      footer = str
      // 规范化换行符，确保一致性
      const normalizedContent = footer.replace(/\r\n/g, '\n').replace(/\r/g, '\n');

      // 匹配脚注定义：以 [^编号]: 开头，直到换行符
      const footnoteRegex = /\[\^\d+\]:\s*[^\n]*/g;
      const matches = normalizedContent.match(footnoteRegex) || [];

      // 清理匹配结果，去除前后多余空格
      const footnoteDefinitions = matches.map(def => def.trim());
      str = think + str;
      const resxx = await this.WriteChatGPTLog({
        Question: prompt,
        Answer: str,
      });
      if (resxx.Data?.SessionID) {
        this.chatClick(
          resxx.Data?.SessionID || this.SessionID,
          ChatTitle,
          TransTime,
          this.Action,
          this.SystemRole
        );
      }
    },
    async sendMessage(event) {
      if (!sessionStorage.getItem("Name")) {
        this.$message.error("发生错误：请先登录帐号");
        return;
      }
      const chackdata = {
        Data: {
          Model: "3.5",
        },
      };
      const check = await connrequest("CheckAiAvailability", chackdata);
      if (check.Status.StatusCode !== 0) {
        this.$message.error("ai使用次数超过当天上限");
        return false;
      }
      if (this.inAnswer) {
        return;
      }
      if (this.inputText === "") {
        return;
      }
      if (this.nowTemplete.Id) {
        const nowData = {
          Data: {
            ClassName: this.tabName,
            Id: this.nowTemplete.Id,
          },
        };
        await connrequest("RecordAiTemplateUseCount", nowData);
      }
      let str = this.inputText;
      let ChatTitle = str.slice(0, 20);
      let TransTime = (new Date().getTime() / 1000).toFixed() * 1;
      if (this.choseRole) {
        if (this.Action === 1) {
          this.messages = [];
          this.apiMessage = [];
        }
        let arr = JSON.parse(JSON.stringify(this.historyList));
        const hasDuplicate = arr.some(
          (item) => item.ChatTitle == this.inputText
        );
        if (hasDuplicate) {
          let obj = {
            ChatTitle: ChatTitle,
            uuid: null,
            isEdit: true,
            edit: false,
            TransTime: TransTime,
          };
          this.historyList.unshift(obj);
          this.messages = [];
          this.TransTime = obj.TransTime;
          this.choseRole = false;
          this.SessionID = undefined;
          this.ChatTitle = ChatTitle;
        } else {
          let obj = {
            ChatTitle: ChatTitle,
            uuid: null,
            isEdit: true,
            edit: false,
            TransTime: TransTime,
          };
          this.historyList.unshift(obj);
          this.choseRole = false;
          this.SessionID = undefined;
          this.ChatTitle = ChatTitle;
        }
      }
      if (event.shiftKey) {
        this.inputText += "\n";
      } else {
        // 执行发送信息的操作
        if (this.loading === true) {
          return false;
        }
        // this.loading = true
        let prompt = "";
        prompt = this.inputText;
        const userMessage = {
          content: prompt,
          role: "user",
          created: parseTime(Date.parse(new Date())),
        };
        this.messages.push(userMessage);
        this.inputText = "";
        // 发送信息后返回div底部
        this.$nextTick(() => {
          this.$refs.chatMessages.scrollTop =
            this.$refs.chatMessages.scrollHeight;
        });
        // 向后端发送请求，获取机器人的回复
        this.xxxxxx(prompt, ChatTitle, TransTime);
      }
    },
    clearMessage() {
      this.$confirm("是否清空会话?", "清空会话", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning",
      })
        .then(() => {
          this.messages = [];
          this.apiMessage = [
            { role: "system", content: "you are a helpful assistant." },
          ];
          this.$message({
            type: "success",
            message: "会话已清空!",
          });
        })
        .catch(() => {
          this.$message({
            type: "info",
            message: "已取消",
          });
        });
    },
    // 删除绘画回复前的json
    removeJsonPrefix(str) {
      let trimmedString = "";
      try {
        // 尝试解析 JSON
        const jsonObject = JSON.parse(str);
        // 检查 JSON 对象是否同时包含 "size" 和 "prompt" 键
        if (
          jsonObject &&
          typeof jsonObject === "object" &&
          "size" in jsonObject &&
          "prompt" in jsonObject
        ) {
          // 找到第一个 '}' 的位置，这标志着 JSON 对象的结束
          const jsonEndIndex = str.indexOf("}") + 1;
          if (jsonEndIndex > 0) {
            // 截取 JSON 结束位置之后的字符串
            trimmedString = str.substring(jsonEndIndex).trim(); // 使用 trim() 去除可能的前后空格
          } else {
            // 如果找不到 '}'，理论上不应该发生，除非 JSON 格式非常不完整，但为了保险起见，这里按原样处理
            trimmedString = str;
          }
        } else {
          // JSON 对象不符合条件（缺少 "size" 或 "prompt" 或不是对象），不去除 JSON，保持原样
          trimmedString = str;
        }
      } catch (e) {
        // JSON 解析失败，说明字符串开头不是有效的 JSON，不去除，保持原样
        trimmedString = str;
      }
      return trimmedString;
    },
    copy(data) {
      let elInput = document.createElement("textarea");
      elInput.value = data;
      document.body.appendChild(elInput);
      // 选择对象
      elInput.select();
      // 执行浏览器复制命令
      this.$message.success("复制成功");
      document.execCommand("Copy");
      elInput.remove();
    },
    speak(value) {
      this.isSpeak = false;
      // 获取选中的文本
      const selection = window.getSelection().toString();
      speakText(selection || value);
    },
    Stopspeak() {
      this.isSpeak = true;
      speechSynthesis.cancel();
    },
    startRecognition() {
      // 检查浏览器是否支持 Web Speech API
      if (!("webkitSpeechRecognition" in window)) {
        alert("抱歉，您的浏览器不支持语音转文字功能。");
        return;
      }
      // 创建识别对象
      this.recognition = new window.webkitSpeechRecognition();
      this.recognition.continuous = false; // 设置为 false 以进行一次语音识别
      this.recognition.interimResults = false; // 不需要中间结果
      this.recognition.lang = "zh-CN"; // 设置语言为中文
      // 处理结果
      this.recognition.onresult = (event) => {
        this.inputText = event.results[0][0].transcript; // 获取转化后的文本Loading
      };
      // 处理错误
      this.recognition.onerror = (event) => {
        console.error("识别错误:", event.error);
      };
      // 开始识别
      this.recognition.start();
    },
    async GetDictKnowledgeClass() {
      const res = await connrequest("GetDictKnowledgeClass");
      const classList = res.Data.map(item => ({
        ...item,
        label: item.Class,
        value: item.ID,
      }));
      this.classList = treeing(classList);
    },
    async GetUserChatCollectClass() {
      const res = await connrequest("GetUserChatCollectClass");
      this.classList = res.Data;
    },
    async joinKnowledge(val, index) {
      await this.GetDictKnowledgeClass()
      this.joinType = 1
      this.dialogForm = {
        Title: this.messages[index - 1].content.substring(0, 20),
        Class: this.classList[0]?.children?.[0]?.ID,
        Property: 1,
        ContentLink: val,
      };
      this.openDialog();
    },
    async joinCollect(val, index) {
      await this.GetUserChatCollectClass()
      this.joinType = 2
      this.dialogForm = {
        Title: this.messages[index - 1].content.substring(0, 20),
        Class: this.classList[0]?.Class,
        Property: 1,
        ContentLink: val,
      };
      this.openDialog();
    },
    // 弹窗提交数据
    async submitDialog(submitdata, Action) {
      // 将字符串转为Blob
      const blob = new Blob([submitdata.ContentLink], { type: "text/plain" }); // 指定MIME类型为text/plain
      // 将Blob转为File对象，指定文件名
      const file = new File([blob], "test.txt", { type: "text/plain" });
      let formData = new FormData();
      formData.append("CmdCode", "UploadFileToTmp");
      formData.append("file", file);
      const fileUUID = await uploadfile(formData);
      this.dialogVisible = false;
      // 在这里处理提交的数据，调用 EditDictKnowledge 保存数据
      try {
        const data = {
          Data: {
            Action: 1,
            Detail: {
              UserID: sessionStorage.getItem("Name"),
              ...submitdata,
              ContentLink: fileUUID.Data.UUID,
            },
          },
        };
        const res = await connrequest(this.joinType === 1 ? "EditDictKnowledge" : "EditUserChatCollect", data);
        if (res && res.Status.StatusCode === 0) {
          //  添加成功，刷新表格数据
          ElMessage.success("添加成功"); //  显示添加成功的提示信息;
        } else {
          ElMessage.error("添加失败"); //  添加失败，处理错误信息
        }
      } catch (error) {
        ElMessage.error(error.Status.Msg2Client); //  处理请求错误,显示请求错误的提示信息
      }
    },
    // 打开弹窗
    openDialog() {
      this.dialogVisible = true;
    },

    // 关闭弹窗
    closeDialog() {
      this.dialogVisible = false;
    },

  },
};
</script>

<style scoped lang="scss">
.wrap {
  position: relative;
  font-family: "Microsoft YaHei", Arial, sans-serif;
  display: flex;
  height: calc(100vh - 70px);
  background: #f0f2f5;
  padding: 10px;

  .ArrowLeftBold {
    position: absolute;
    font-size: 20px;
    top: 45%;
    left: 270px;
    border-radius: 5px 0px 0px 5px;
    background: #459ffc;
    height: 30px;
    z-index: 100;
    cursor: pointer;

    svg {
      color: #fff;
    }
  }

  .database-dropdown {
    min-width: 135px;
    margin-left: 10px;
  }

  .database-dropdown .el-tag {
    margin: 2px;
    max-width: 80px;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  /* 确保下拉箭头颜色与按钮一致 */
  :deep(.el-button .el-icon--right svg) {
    color: #fff !important;
  }
}

.chat-list {
  position: relative;
  height: calc(100vh - 90px);
  background: #fff;
  margin-right: 10px;
  padding: 10px;
  overflow-y: auto;

  .list-button {
    cursor: pointer;
    display: block;
    padding: 10px;
    margin-bottom: 15px;
    border: 1px dashed #ddd;
    text-align: center;
  }

  .lookMore {
    font-size: 14px;
    color: #000;
    font-weight: 600;
    color: #8c8e8e;
    text-align: center;
    cursor: pointer;
  }

  .list-chatname {
    display: flex;
    justify-content: space-between;
    font-size: 14px;
    padding: 10px;
    margin-bottom: 10px;
    cursor: pointer;
    border-radius: 8px;

    i {
      margin-right: 5px;
    }

    &:hover {
      // color: #409eff;
      background: #eeeeee;
    }
  }

  .list-name {
    display: flex;
    align-items: center;

    i {
      margin-right: 15px;
    }
  }

  .selected {
    // color: #409eff;
    background: #eeeeee;
  }

  .list-edit {
    display: flex;
    align-items: center;
  }
}

.chat-container {
  position: relative;
  display: flex;
  flex-direction: column;
  background: #fff;
}

.chat-header {
  background-color: #409eff;
  color: white;
  text-align: center;
}

.choseRole {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(218px, 1fr));
  grid-gap: 15px;
  /* 设置行和列之间的间距为 15px */
  grid-template-rows: repeat(auto-fit, minmax(195px, 1fr));
  max-height: calc(100vh - 250px);
  border-radius: 5px;
  overflow-y: auto;
  padding: 0 0 0 15px;
  color: #8c8c8c;
  background-color: #fff;

  .role-wrap {
    margin-right: 15px;
    border: 1px solid #f0f0f0;
    padding: 15px;
    border-radius: 5px;
    cursor: pointer;
  }

  .choseRole::after {
    content: "";
    flex: auto;
  }

  .role {
    font-size: 16px;
    color: #141414;
    white-space: nowrap;
    /* 不换行 */
    overflow: hidden;
    /* 隐藏溢出部分 */
    text-overflow: ellipsis;
    /* 显示省略号 */
  }

  .introduce {
    font-size: 14px;
    padding-bottom: 10px;
    border-bottom: 1px solid #f0f0f0;
    white-space: nowrap;
    /* 不换行 */
    overflow: hidden;
    /* 隐藏溢出部分 */
    text-overflow: ellipsis;
    /* 显示省略号 */
  }

  .explain {
    height: 75px;
    overflow-y: auto;
    font-size: 12px;
    color: #000;
    line-height: 25px;
    display: -webkit-box;
    // -webkit-line-clamp: 3; /* 指定显示的行数 */
    // -webkit-box-orient: vertical; /* 设置为垂直方向 */
    // overflow: hidden;
    // text-overflow: ellipsis;
  }

  ::-webkit-scrollbar {
    width: 0px;
  }
}

::-webkit-scrollbar {
  width: 5px;
}

/* 修改滚动条的轨道颜色 */
::-webkit-scrollbar-track {
  width: 5px;
  background-color: #f1f1f1;
}

/* 修改滚动条的滑块颜色 */
::-webkit-scrollbar-thumb {
  background-color: #ccc;
}

/* 修改滚动条的滑块形状 */
::-webkit-scrollbar-thumb:hover {
  background-color: #555;
}

/* 修改滚动条的角落 */
::-webkit-scrollbar-corner {
  background-color: #f1f1f1;
}

.sendInput {
  position: relative;
  padding: 20px;
  max-width: 80%;
  margin: 30px auto 0;

  .sendButton {
    position: absolute;
    bottom: 30px;
    right: 40px;
  }

  .voiceInput {
    color: #b8b8b8;
    position: absolute;
    bottom: 8px;
    right: 80px;
    cursor: pointer;
  }

  .cosplay {
    color: #b8b8b8;
    position: absolute;
    bottom: 8px;
    right: 50px;
    cursor: pointer;
  }

  .changeModel {
    position: absolute;
    left: 20px;
    top: -20px;
    color: #b8b8b8;
    position: absolute;
    bottom: 8px;
    right: 80px;
    cursor: pointer;
  }
}

.voiceInput2 {
  color: #b8b8b8;
  position: absolute;
  bottom: 8px;
  right: 100px;
  cursor: pointer;
}

.chat-main {
  flex: 1;
  padding: 20px;
  padding-bottom: 120px;
  background: #ffffff;
}

.chat-messages {
  height: calc(100vh - 220px);
  overflow-y: auto;
  font-size: 14px;
  line-height: 25px;
  display: flex;
  flex-direction: column;

  .seeMore {
    text-align: center;
    cursor: pointer;
    color: #409eff;
  }

  .regenerate {
    cursor: pointer;
    position: absolute;
    right: 10px;
    bottom: 5px;

    .el-icon svg {
      font-size: 28px !important;
      color: red;
    }
  }
}

.suspend {
  position: relative;
  z-index: 10000;
  text-align: center !important;
  cursor: pointer;
  color: #f56c6c;
}

.chat-avatar {
  padding-top: 10px;

  img {
    width: 35px;
    border-radius: 50%;
  }
}

.chat-content {
  position: relative;
  display: flex;
  flex-direction: column;
}

.el-icon svg {
  color: #8c8e8e;
}

pre {
  // background-color: #f4f6f8;
  padding: 10px;
  border-radius: 10px;
}

.chat-message-left {
  width: 50vw;
  display: flex;
  border-radius: 5px;
  margin: 10px 0;
  align-self: flex-start;

  .chat-message-text {
    width: 100%;
    overflow-y: auto;
    width: 50vw;
    min-width: 1024px;
    align-self: flex-start;
    margin-left: 10px;
    border-radius: 5px;
    padding: 0 10px;
    word-wrap: break-word;
    background-color: #f4f6f8;
  }

  .chat-time {
    align-self: flex-start;
    font-size: 12px;
    color: #ccc;
    padding-left: 10px;
  }

  .copy {
    color: #409eff;
    cursor: pointer;
  }
}

.chat-message-right {
  display: flex;
  max-width: 80%;
  border-radius: 5px;
  margin: 10px 0;
  align-self: flex-end;

  .chat-message-text {
    color: #fff;
    align-self: flex-end;
    margin-right: 10px;
    border-radius: 5px;
    padding: 0 10px;
    background-color: #409EFF;
  }

  .chat-time {
    font-size: 12px;
    color: #ccc;
    padding-right: 10px;
    align-self: flex-end;
  }
}

.chat-input {
  flex: 1;
  margin-right: 10px;
}

.chat-footer {
  position: absolute;
  bottom: 40px;
  width: 80%;
  left: 10%;
  display: flex;
  align-items: center;
  padding: 10px;

  .el-icon-delete {
    font-size: 18px;
    margin-right: 10px;
  }

  ::-webkit-scrollbar {
    display: none;
  }
}

.dialog-footer {
  display: inline-block;
  display: flex;
  align-items: right;
  justify-content: flex-end;
  padding-bottom: 40px;
  padding-right: 20px;
}

.day7::before {
  // content: "最近7天：" !important;
  color: #dddddd;
}

:focus {
  outline: 0;
}

:deep(.el-tabs__nav:first-child::before) {
  font-family: "Microsoft YaHei", Arial, sans-serif;
  font-size: 14px;
  padding-top: 10px;
  padding-left: 10px;
  padding-right: 10px;
  content: "模板：";
  color: #a3a3a3;
}
</style>

<style>
/** 列表样式 **/

code {
  font-size: 14px;
  font-family: "微软雅黑" !important;
}

.markdown ol {
  list-style-type: decimal;
  padding-left: 40px;
}

.markdown ul {
  list-style-type: disc;
  padding-left: 40px;
}
.markdown a{
  color: #2d92f9;
}
a:-webkit-any-link{
  color: #2d92f9;
}


.code-block-header {
  width: 100%;
  background: #000 !important;
  display: flex;
  justify-content: space-between;
  color: #dddddd;
}

.code-block-header__lang,
.code-block-header__copy {
  padding: 5px;
  cursor: pointer;
}

/* .demo-tabs{ */
.el-tabs__item {
  font-size: 14px;
  padding: 0 10px;
}

.el-dialog {
  padding: 0px;
}

.el-dialog__body {
  padding: 16px;
}

/* 隐藏所有脚注引用标记 */
a.footnote-ref,
.footnote-ref {
  display: none !important;
}

/* 精准隐藏脚注定义行末尾的引用标记 */
:deep(.chat-message-text)::after {
  content: none !important;
}

/* 隐藏标准脚注引用（双重保险） */
.footnote-ref,
[class*="citation"] {
  display: none !important;
}


</style>